<?php
/**
 * Enter description here...
 *
 * @package if
 * @subpackage module.db.drivers
 * @since 1.0.1
 */
class IDbPostgresDriver extends IDbDriver {
	protected $startQuote = "\"";
	protected $endQuote = "\"";	
	
	protected $commands = array(
		"begin"    => "BEGIN",
		"commit"   => "COMMIT",
		"rollback" => "ROLLBACK"
	);
	
	protected $metaTableSQL = "select tablename,'T' from pg_tables where tablename not like 'pg\_%' and schemaname  not in ( 'pg_catalog','information_schema') union select viewname,'V' from pg_views where viewname not like 'pg\_%'  and schemaname  not in ( 'pg_catalog','information_schema')";
	
	protected $default = array(
		"port" => 5432
	);
	
	function __construct(array $config) {
		parent::__construct($config);
		if (!extension_loaded("pgsql")) {
			throw new IDbException("pgsql extension not be loaded", 0x100078);
		}
	}
	
	/**
	 * Enter description here...
	 *
	 * @param unknown_type $name
	 * @return array
	 */
	function describeTable($name) {
		$keys = $this->fetchAll($this->nativeExec("SELECT ic.relname AS index_name, a.attname AS column_name,i.indisunique AS unique_key, i.indisprimary AS primary_key FROM pg_class bc, pg_class ic, pg_index i, pg_attribute a WHERE bc.oid = i.indrelid AND ic.oid = i.indexrelid AND (i.indkey[0] = a.attnum OR i.indkey[1] = a.attnum OR i.indkey[2] = a.attnum OR i.indkey[3] = a.attnum OR i.indkey[4] = a.attnum OR i.indkey[5] = a.attnum OR i.indkey[6] = a.attnum OR i.indkey[7] = a.attnum) AND a.attrelid = bc.oid AND bc.relname = '{$name}'"), IDb::FETCH_ASSOC);
		$keys = if_array_combine($keys, "column_name");
		
		$rows = $this->fetchAll($this->nativeExec("SELECT a.attname,t.typname,a.attlen,a.atttypmod,a.attnotnull,a.atthasdef,a.attnum FROM pg_class c, pg_attribute a,pg_type t WHERE relkind in ('r','v') AND (c.relname='{$name}' or c.relname = lower('{$name}')) and a.attname not like '....%%'
AND a.attnum > 0 AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum"), IDb::FETCH_NUM);
		$fields = array();
		
		foreach ($rows as $row) {
			$fld = new stdClass();
			$fld->name = $row[0];
			$fld->type = $row[1];
			$fld->max_length = $row[2];
			$fld->attnum = $row[6];
			
			if ($fld->max_length <= 0) $fld->max_length = $row[3]-4;
			if ($fld->max_length <= 0) $fld->max_length = -1;
			if ($fld->type == 'numeric') {
				$fld->scale = $fld->max_length & 0xFFFF;
				$fld->max_length >>= 16;
			}
			// dannym
			// 5 hasdefault; 6 num-of-column
			$fld->has_default = ($row[5] == 't');
			if ($fld->has_default) {
				$fld->default_value = $rsdefa[$row[6]];
			}

			//Freek
			$fld->not_null = $row[4] == 't';

			// Freek
			if (isset($keys[$fld->name]) && $keys[$fld->name]['primary_key'] == 't') 
				$fld->primary_key = true;
			if (isset($keys[$fld->name]) && $keys[$fld->name]['unique_key'] == 't') 
				$fld->unique = true; 
			
			$fld->data_type = $this->dataType($fld->type);
			$fields[$fld->name] = get_object_vars($fld);
		}
		return $fields;
	}	
	
	protected function nConnect() {
		$conn = null;
		//连接
		$conn  = "host='{$this->config['host']}' port='{$this->config('port')}' dbname='{$this->config['dbname']}' ";
		$conn .= "user='{$this->config['username']}' password='{$this->config['password']}'";
		
		if (!$this->config("persist")) {
			$conn = @pg_connect($conn, PGSQL_CONNECT_FORCE_NEW);
		}
		else {
			$conn = @pg_connect($conn);
		}
		if (!$conn) {
			throw new IDbException("Can't connect to PostgreSQL server on '" . $this->config["host"] . "'", 0x100079);
		}
		if ($this->config("charset")) {
			pg_set_client_encoding($conn, $this->config["charset"]);
		}
		return $conn;
	}
	
	protected function nClose() {
		return $this->connect() ? pg_close($this->connect()) : true;
	}
	
	function lastInsertId($name = null) {
		return pg_last_oid($this->connect());
	}
	
	function nLimit($sql, $count, $offset = 0) {
		return $sql . " LIMIT {$count} OFFSET {$offset}";
	}
	
	protected function nQuote($data) {
		if (is_int($data) || is_float($data)) {
			return $data;
		}
		if(is_null($data)) {
			return "NULL";
		}
		return "'" . pg_escape_string($data, $this->connect()) . "'";
	}
	
	function exec($sql) {
		$this->_log("execute:{$sql}");
		$result = @pg_query($this->connect(), $sql);
		$this->_free();
		return pg_affected_rows($result);
	}
	
	function nativeExec($sql) {
		$result = @pg_query($this->connect(), $sql);
		$this->_free();
		return $result;
	}
	
	/**
	 * Enter description here...
	 *
	 * @param unknown_type $result
	 * @param unknown_type $fetchType
	 * @param unknown_type $arguments
	 * @return unknown
	 * @todo FETCH_OBJ是支持class名
	 */
	function fetch($result, $fetchType = IDb::FETCH_BOTH, $columnIndex = 0) {
		switch ($fetchType) {
			case IDb::FETCH_BOTH:
				return pg_fetch_array($result, null, PGSQL_BOTH);
				break;
			case IDb::FETCH_ASSOC:
				return pg_fetch_array($result, NULL, PGSQL_ASSOC);
			case IDb::FETCH_NUM:
				return pg_fetch_array($result, null, PGSQL_NUM);
			case IDb::FETCH_OBJ:
				return pg_fetch_object($result);
			case IDb::FETCH_COLUMN:
				$row = pg_fetch_array($result);
				if (!empty($row)) {
					if (array_key_exists($columnIndex, $row)) {
						return $row[$columnIndex];
					}
				}
		}
		return null;
	}
	
	function error() {
		$error = pg_last_error($this->connect());
		if (!$error) {
			return array();
		}
		return array(
			"code" => 0,
			"message" => $error
		);
	}
	
	private function _free($result = null) {
		if (gettype($result) == "resource") {
			pg_free_result($result);
		}
		$error = $this->error();
		if (!empty($error)) {
			throw new IDbException($error["message"], $error["code"]);
		}
	}
	
	function rowCount($result) {
		return pg_num_rows($result);
	}
	
	function move($result, $offset) {
		return pg_result_seek($result, $offset);
	}	
}


?>